package com.dbky.alg.browser.config;

import com.dbky.alg.browser.CustomerAuthenticationFailureHandler;
import com.dbky.alg.browser.CustomerAuthenticationSuccessHandler;
import com.dbky.alg.browser.session.AlgSessionInformationExpiredStrategy;
import com.dbky.alg.core.authentication.mobile.SmsCodeAuthenticationSecurityConfig;
import com.dbky.alg.core.properties.AlgSecurityProperties;
import com.dbky.alg.core.validate.code.ValidateCodeFilter;
import com.dbky.alg.core.validate.code.ValidateSmsCodeFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.PriorityOrdered;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import org.springframework.social.security.SpringSocialConfigurer;

import javax.sql.DataSource;

/**
 * @Auther: tianchao
 * @Date: 2021/12/11 00:56
 * @Description:
 */
@Configuration
@EnableWebSecurity
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private AlgSecurityProperties algSecurityProperties;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;

    // 这里目前注入的其实就是 之前写的开启social的配置类SocialConfig
    @Autowired
    private SpringSocialConfigurer algSpringSocialConfigurer;

    @Autowired
    private InvalidSessionStrategy invalidSessionStrategy;

    @Autowired
    private SessionInformationExpiredStrategy sessionInformationExpiredStrategy;

    @Autowired
    private LogoutSuccessHandler logoutSuccessHandler;

    @Bean
    public CustomerAuthenticationFailureHandler customerAuthenticationFailureHandler(){
        return new CustomerAuthenticationFailureHandler();
    }
    @Bean
    public CustomerAuthenticationSuccessHandler customerAuthenticationSuccessHandler(){
        return new CustomerAuthenticationSuccessHandler();
    }

    @Bean
    public PersistentTokenRepository persistentTokenRepository(){
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        //tokenRepository.setCreateTableOnStartup(true);
        return tokenRepository;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter(customerAuthenticationFailureHandler());
        validateCodeFilter.setSecurityProperties(algSecurityProperties);
        validateCodeFilter.afterPropertiesSet();

        ValidateSmsCodeFilter validateSmsCodeFilter = new ValidateSmsCodeFilter(customerAuthenticationFailureHandler());
        validateSmsCodeFilter.setSecurityProperties(algSecurityProperties);
        validateSmsCodeFilter.afterPropertiesSet();
        http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class);
        http.addFilterBefore(validateSmsCodeFilter, UsernamePasswordAuthenticationFilter.class);
        http.formLogin()
                .loginProcessingUrl("/authentication/form")
                .loginPage("/authentication/require")
                .failureHandler(customerAuthenticationFailureHandler())
                .successHandler(customerAuthenticationSuccessHandler())
                .and()
                    .rememberMe()
                    .tokenRepository(persistentTokenRepository())
                    .tokenValiditySeconds(algSecurityProperties.getRememberMeSeconds())
                    .userDetailsService(userDetailsService)
                .and()
                .sessionManagement()
                    //.invalidSessionUrl("/session/invalid")
                    .invalidSessionStrategy(invalidSessionStrategy)
                    .maximumSessions(algSecurityProperties.getBrowser().getSession().getMaximumSessions())
                    .expiredSessionStrategy(sessionInformationExpiredStrategy)
                    .maxSessionsPreventsLogin(algSecurityProperties.getBrowser().getSession().isMaxSessionsPreventsLogin())
                .and()
                .and()
                .logout()
                    //解决退出登录 session失效后 让session失效问题，也许会有bug
                    // 设置为false解决问题 但是不对，不清除session会有影响,至少影响服务器
                    //deleteCookies("JSESSIONID") 加入了一个退出登录处理器
                    //时jessionID删除掉 ，但是重定向的时候还是有JessionID 这是疑惑的地方,
                    // TODO 但是分给了一个新的JESSIONID ,这个session就不会被认为是失效的，解决了被判定
                    //为session失效的问题
                    .invalidateHttpSession(true)
                    .logoutUrl("/signOut")
                     //通过源码可以知道
                    .logoutSuccessUrl("/alg-logout.html")
                    .logoutSuccessHandler(logoutSuccessHandler)
                    .deleteCookies("JSESSIONID")

                .and()
                .authorizeRequests()
                .antMatchers(
                        "/alg-signIn.html",
                        "/authentication/require",
                        algSecurityProperties.getBrowser().getLoginPage(),
                        "/code/image",
                        "/code/sms",
                        "/auth/**",
                        "/session/invalid",
                        "/alg-logout.html")
                .permitAll()
                .antMatchers("/me").hasRole("alg")
                .antMatchers("/create").hasAuthority("/create")
                .antMatchers("/update").hasAuthority("/update")
                .anyRequest()
                .authenticated()
                .and().csrf().disable();
            http.apply(smsCodeAuthenticationSecurityConfig);
            http.apply(algSpringSocialConfigurer);


    }
}
